#include "inode.h"
#include <iostream>
#include <stdio.h>
#include "lib/e7convert.h"


Inode::Inode(FILE* device, unsigned long offset) : Block(device, offset)
{
    inode = new inode_t();
    read(inode, sizeof(inode_t));
}

Inode::~Inode()
{
    delete inode;
    delete ind1;
    delete ind2;
    delete ind3;
}

ulong Inode::getModeTypeFile()
 {
    return readUnsignedInteger(inode->modeTypeFile, USHORT);
}

ulong Inode::getNumberOfLinks()
{
    return readUnsignedInteger(inode->numberOfLinks, USHORT);
}

ulong Inode::getOwnerUserId()
{
    return readUnsignedInteger(inode->ownerUserId, USHORT);
}

ulong Inode::getGroupUserId()
{
    return readUnsignedInteger(inode->groupUserId, USHORT);
}

ulong Inode::getFileSize()
{
    return readUnsignedInteger(inode->fileSize, UINT);
}

ulong * Inode::getDataBlockAdresses()
{
    ulong * dataBlockAddresses = new ulong[INODE_DATALIST_SIZE];
    for(int i = 0; i < INODE_DATALIST_SIZE; i++) {
        dataBlockAddresses[i] = readUnsignedInteger(inode->dataBlockAddresses[i], INODE_DATABLOCK_SIZE);
    }
    return dataBlockAddresses;
}

ulong Inode::getLastAccessed()
{
        return readUnsignedInteger(inode->lastAccessed, UINT);
}

char * Inode::getLastAccessedAsString()
{
    time_t epch = getLastAccessed();
    return asctime(gmtime(&epch));
}

ulong Inode::getLastModified()
{
        return readUnsignedInteger(inode->lastModified, UINT);
}

char * Inode::getLastModifiedAsString()
{
    time_t epch = getLastModified();
    return asctime(gmtime(&epch));
}

ulong Inode::getLastChanged()
{
        return readUnsignedInteger(inode->lastChanged, UINT);
}

char * Inode::getLastChangedAsString()
{
    time_t epch = getLastChanged();
    return asctime(gmtime(&epch));
}

std::vector<long> * Inode::getAllDataBlockAdresses()
{
	std::vector<long> * tmpList = new std::vector<long>();
	unsigned long * addresses = this->getDataBlockAdresses();

	for(int k=0; k<INODE_DATALIST_SIZE; k++)
	{
		unsigned long blockAddress = addresses[k];

		//we don't want to process empty addresses
		if(blockAddress != 0)
		{
			// no indirect blocks
			if(k < 10)
			{
				tmpList->push_back(blockAddress);
			}
			// indir 1
			else if(k == 10)
			{
				//cout << "load level 1" << endl;
				ind1 = new IndirectBlock(device, blockAddress * BLOCKSIZE, 1);
				std::vector<long> * tmp2 = ind1->getAllAddressBlocks();

				for(std::vector<long>::iterator iter = tmp2->begin(); iter != tmp2->end(); ++iter)
				{
					tmpList->push_back((*iter));
				}

				delete tmp2;
			}
			// indir 2
			else if(k == 11)
			{
				//cout << "load level 2" << endl;
				ind2 = new IndirectBlock(device, blockAddress * BLOCKSIZE, 2);
				vector<long> * tmp2 = ind2->getAllAddressBlocks();

				for(std::vector<long>::iterator iter = tmp2->begin(); iter != tmp2->end(); ++iter)
				{
					tmpList->push_back((*iter));
				}

				delete tmp2;
			}
			// indir 3
			else if(k == 12)
			{
				//cout << "load level 3" << endl;
				ind3 = new IndirectBlock(device, blockAddress*BLOCKSIZE, 3);
				std::vector<long> * tmp2 = ind3->getAllAddressBlocks();

				for(std::vector<long>::iterator iter = tmp2->begin(); iter != tmp2->end(); ++iter)
				{
					tmpList->push_back((*iter));
				}

				delete tmp2;
			}
		}
	}
	return tmpList;
}


void Inode::print()
{
	getAllDataBlockAdresses();
	printf("-------------------------------------------\n");
	printf("ModeType: %#o Type: %#o Mode: %#o \n", getModeTypeFile(), (getModeTypeFile() & 0170000), (getModeTypeFile()%512));
    printf("UID: %d GID: %d \n", getOwnerUserId(), getGroupUserId());
    printf("Links: %d Size: %d\n",getNumberOfLinks(), getFileSize());
    printf("Address: ");

    ulong * addresses = getDataBlockAdresses();

    for(int i = 0; i < INODE_DATALIST_SIZE; i++)
    {
        printf("%d ", addresses[i]);
    }
    printf("\n");

    printf("Direct blocks: ");
	for(int i = 0; i < 10; i++)
	{
		if(addresses[i]!=0) printf("%d ", addresses[i]);
	}
	printf("\n");

    if(ind1)
    {
    	printf("Indirect 1 blocks: %d:\n", addresses[10]);
    	ind1->print();
    	cout << endl;
    }

    if(ind2)
    {
    	printf("Indirect 2 blocks: %d:\n", addresses[11]);
		ind2->print();
		cout << endl;
	}

	if(ind3)
	{
		printf("Indirect 3 blocks: %d:\n", addresses[12]);
		ind3->print();
		cout << endl;
	}

    printf("Last Access: %s", getLastAccessedAsString());
    printf("Last Mod: %s", getLastModifiedAsString());
    printf("Last Changed: %s", getLastChangedAsString());
}


